//: C19:Getmem.h
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 1999
// Copyright notice in Copyright.txt
// Function template for memory
#ifndef GETMEM_H
#define GETMEM_H
#include "../require.h"
#include <cstdlib>
#include <cstring>

template<class T>
void getmem(T*& oldmem, int elems)
{
    typedef int cntr; // Type of element counter
    const int csz = sizeof(cntr); // And size
    const int tsz = sizeof(T);
    if (elems == 0) {
        free(&(((cntr*)oldmem)[-1]));
        return;
    }
    T* p = oldmem;
    cntr oldcount = 0;
    if (p) { // Previously allocated memory
        // Old style:
        // ((cntr*)p)--; // Back up by one cntr
        // New style:
        cntr* tmp = reinterpret_cast<cntr*>(p);
        p = reinterpret_cast<T*>(--tmp);
        oldcount = *(cntr*)p; // Previous # elems
    }
    T* m = (T*)realloc(p, elems * tsz + csz);
    require(m != 0);
    *((cntr*)m) = elems; // Keep track of count
    const cntr increment = elems - oldcount;
    if (increment > 0) {
        // Starting address of data:
        long startadr = (long)&(m[oldcount]);
        startadr += csz;
        // Zero the additional new memory:
        memset((void*)startadr, 0, increment * tsz);
    }
    // Return the address beyond the count:
    oldmem = (T*)&(((cntr*)m)[1]);
}

template<class T>
inline void freemem(T * m)
{
    getmem(m, 0);
}

#endif // GETMEM_H ///:~
